// 虚拟滚动组件
import { useEffect, useRef, useState } from 'react';
import { useScroll, useSize } from 'ahooks';

const sumListValue = (list, endIndex) => { // 列表求和
    let sum = 0;
    for (let i = 0; i < endIndex; i++) {
        sum += list[i];
    }
    return sum;
};

/**
 * 虚拟滚动组件
 * @param renderItem 渲染函数
 * @param list 列表
 * @param height 每一项高度
 * @param style 样式
 */
const VirtualScroll = ({ renderItem, list, height = 30, style = { height: 300 } }) => {
    const box = useRef(null); // 获取容器
    const scroll = useScroll(box); // 获取滚动信息
    const size = useSize(box); // 获取容器大小
    const [position, setPosition] = useState({ // 记录位置
        start: 0,
        end: 0,
    });

    useEffect(() => {
        if (size?.height) { // 如果容器高度存在
            if (height.constructor === Array) {
                let top = 0;
                for (let i = 0; i < height.length; i++) {
                    top += height[i];
                    if (scroll?.top < top) {
                        setPosition({ // 记录位置
                            start: i > 2 ? i - 2 : i,
                            end: (() => {
                                let sum = 0;
                                for (let j = i; j < height.length; j++) {
                                    sum += height[j];
                                    if (sum > size.height) {
                                        return j + 2;
                                    }
                                }
                                return height.length + 2;
                            })(), // 计算结束位置
                        });
                        break;
                    }
                }
            } else {
                const start = Math.floor((scroll?.top || 0) / height); // 计算开始位置
                setPosition({ // 记录位置
                    start: start > 2 ? start - 2 : start,
                    end: start + Math.ceil(size?.height / height) + 2, // 计算结束位置
                });
            }
        }
    }, [size?.height, scroll?.top]); // 监听容器高度和滚动信息

    const boxStyle = height.constructor === Array ? {
        height: sumListValue(height, height.length),
        paddingTop: sumListValue(height, position.start),
    } : {
        height: height * list.length,
        paddingTop: position.start * height,
    };
    return (
        <div ref={box} style={{ ...style, overflowY: 'auto' }}>
            {/* 填充容器 */}
            <div style={boxStyle}>
                {
                    list.map((item, index) => {
                        if (position.start <= index && index <= position.end) { // 如果在可视区域内
                            return renderItem(item, index, height.constructor === Array ? height[index] : height);
                        }
                    })
                }
            </div>
        </div>
    );
};
export default VirtualScroll;
